home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Uip / sendmail / sendmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  10.9 KB  |  521 lines

  1. /* sendmail.c: A fake sendmail for those that really need it */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Uip/sendmail/RCS/sendmail.c,v 6.0 1991/12/18 20:42:15 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Uip/sendmail/RCS/sendmail.c,v 6.0 1991/12/18 20:42:15 jpo Rel $
  9.  *
  10.  * $Log: sendmail.c,v $
  11.  * Revision 6.0  1991/12/18  20:42:15  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include <signal.h>
  19. #include <pwd.h>
  20. #include "util.h"
  21. #include "prm.h"
  22. #include "q.h"
  23. #include "adr.h"
  24. #include "retcode.h"
  25. #include "ap.h"
  26. #include <varargs.h>
  27.  
  28. extern  char    *loc_dom_site;
  29. extern    char    *chndfldir;
  30. extern    char     *hdr_822_bp;
  31. extern     char    *ia5_bp;
  32. extern     char    *local_822_chan;
  33. extern UTC    utclocalise();
  34.  
  35. extern struct passwd *getpwuid ();
  36. extern char *getenv();
  37. extern char *dupfpath();
  38.  
  39. static char    *SMTPSRVR = "smtpsrvr";
  40.  
  41. static char    *fullname;    /* sender's full name */
  42. static char    *from;        /* sender's mail address */
  43. static int    verify;
  44. static int    badaddrs;
  45. static int    rewritefrom;
  46. static int    watch;
  47. static int    extract_mode;
  48. static char    *eaddr[1024];
  49. static int    neaddr;
  50. static char     firstline[BUFSIZ];
  51.  
  52. static struct prm_vars prm;
  53. static Q_struct qs;
  54. static RP_Buf rps;
  55. static RP_Buf *rp = &rps;
  56.  
  57. static SFD    die();
  58. static void adios ();
  59.  
  60. static char    tbuf[BUFSIZ];
  61.  
  62. /*ARGSUSED*/
  63. main(argc, argv)
  64. int argc;
  65. char **argv;
  66. {
  67.     struct passwd  *pwdptr;
  68.     register char *p;
  69.     register char **av;
  70.     char **oobto = NULL;
  71.     ADDR    *adr;
  72.  
  73.     uip_init(argv[0]);
  74.     pp_log_norm -> ll_stat |= LLOGTTY;
  75.  
  76.     if ((pwdptr = getpwuid (getuid())) == (struct passwd *) NULL)
  77.         adios (NULLCP, "Unable to locate user's name");
  78.  
  79.     (void) sprintf (tbuf, "%s@%s", pwdptr -> pw_name, loc_dom_site);
  80.     from = strdup (tbuf);
  81.  
  82.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  83.         (void) signal(SIGINT, die);
  84.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  85.         (void) signal(SIGHUP, die);
  86.     (void) signal(SIGTERM, die);
  87.     (void) signal(SIGPIPE, die);
  88.  
  89.     fullname = getenv("NAME");
  90.        /* nobody is going to use this anyway */
  91.        if (p = index(pwdptr->pw_gecos,','))
  92.                *p = 0;
  93.        if (!fullname)
  94.                fullname = strdup(pwdptr->pw_gecos);
  95.  
  96.  
  97.     av = argv;
  98.     while ((p = *++av) != NULL && p[0] == '-') {
  99.         switch (p[1]) {
  100.         case 'b':    /* operations mode */
  101.             switch (p[2]) {
  102.             case 'a':    /* smtp on stdin */
  103.             case 's':    /* smtp on stdin */
  104.                 smtp();
  105.                 exit(98);    /* should never happen */
  106.             case 'm':    /* just send mail */
  107.                 continue;
  108.             case 'v':    /* verify mode */
  109.                 verify++;
  110.                 continue;
  111.             default:
  112.                 adios (NULLCP, "Invalid operation mode %c", p[2]);
  113.             }
  114.             continue;
  115.  
  116.         case 'f':    /* from address */
  117.         case 'r':    /* obsolete -f flag */
  118.             p += 2;
  119.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  120.             {
  121.                 p = *++av;
  122.                 if (p == NULL || *p == '-') {
  123.                     adios (NULLCP, "No \"from\" person");
  124.                     av--;
  125.                     continue;
  126.                 }
  127.             }
  128.             if (rewritefrom) {
  129.                 adios (NULLCP, "More than one \"from\" person");
  130.                 continue;
  131.             }
  132.             from = p;
  133.             rewritefrom++;
  134.             continue;
  135.  
  136.         case 'F':    /* set full name */
  137.             p += 2;
  138.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  139.             {
  140.                 adios (NULLCP, "Bad -F flag");
  141.                 av--;
  142.                 continue;
  143.             }
  144.             fullname = p;
  145.             continue;
  146.  
  147.         case 'h':    /* hop count */
  148.             p += 2;
  149.             if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
  150.             {
  151.                 adios (NULLCP, "Bad hop count (%s)", p);
  152.                 av--;
  153.                 continue;
  154.             }
  155.             continue;    /* Ignore */
  156.  
  157.         case 't':    /* read recipients from message */
  158.             extract_mode = 1;
  159.             continue;
  160.  
  161.  
  162.         case 'v':    /* give blow-by-blow description */
  163.             watch++;
  164.             continue;
  165.  
  166.         case 'T':    /* set timeout interval */
  167.         case 'C':    /* select configuration file (already done) */
  168.         case 'c':    /* connect to non-local mailers */
  169.         case 'd':    /* debug */
  170.         case 'e':    /* error message disposition */
  171.         case 'i':    /* don't let dot stop me */
  172.         case 'm':    /* send to me too */
  173.         case 'n':    /* don't alias */
  174.         case 'o':    /* set option, handled in line */
  175.         case 's':    /* save From lines in headers */
  176.             continue;
  177.         }    
  178. }
  179.  
  180.     setuid(getuid());
  181.  
  182.     prm_init (&prm);
  183.     prm.prm_opts = PRM_ACCEPTALL;
  184.     q_init (&qs);
  185.     qs.inbound = list_rchan_new (loc_dom_site, local_822_chan);
  186.     qs.encodedinfo.eit_types = list_bpt_new (hdr_822_bp);
  187.     list_bpt_add (&qs.encodedinfo.eit_types, list_bpt_new (ia5_bp));
  188.  
  189.     if (rp_isbad (io_init (rp)) ||
  190.         rp_isbad (io_wprm (&prm, rp)) ||
  191.         rp_isbad (io_wrq (&qs, rp)))
  192.         adios (NULLCP, "Unable to submit mail at this time: %s",
  193.                rp -> rp_line);
  194.  
  195.     adr = adr_new (from, AD_822_TYPE, 0);
  196.     adr -> ad_status = AD_STAT_DONE;
  197.     adr -> ad_resp = NO;
  198.     if (rp_isbad (io_wadr (adr, AD_ORIGINATOR, rp)))
  199.         adios (NULLCP, "Unable to submit mail from %s: %s",
  200.             from, rp -> rp_line);
  201.     adr_tfree (adr);
  202.  
  203.     if (*av == NULL && !extract_mode) {
  204.         adios (NULLCP, "Usage: /usr/lib/sendmail [flags] addr...");
  205.     }
  206.     read_header ();
  207.     oobto = av;
  208.     while (*av)
  209.         send_address(*av++);
  210.     if (extract_mode) {
  211.         int i;
  212.  
  213.         for (i = 0; i < neaddr; i++)
  214.             send_address (eaddr[i]);
  215.     }
  216.     if (rp_isbad (io_adend (rp)))
  217.         adios (NULLCP, "Problem with address list.");
  218.        if (verify) {
  219.         io_end(NOTOK);
  220.         exit(badaddrs ? 1 : 0);
  221.     }
  222.     if (rp_isbad (io_tinit (rp)) || rp_isbad (io_tpart (hdr_822_bp, 0, rp)))
  223.         adios (NULLCP, "Problem initialising for text: %s", rp -> rp_line);
  224.  
  225.     doheader(oobto);
  226.  
  227.     exit(dobody());
  228. }
  229.  
  230. static struct qbuf *Header;
  231. static struct qbuf *qbase;
  232. static int nleft;
  233. static char *qbptr;
  234.  
  235. static void qb_read_init (qp)
  236. struct qbuf *qp;
  237. {
  238.     char *cp;
  239.     qbase = qp;
  240.  
  241.     cp = index (qp -> qb_data, ':');
  242.     if (cp == NULL)
  243.         adios (NULLCP, "Internal error - missing ':'");
  244.     cp ++;
  245.     nleft = qp -> qb_len - (cp - qp -> qb_data);
  246.     qbptr = cp;
  247. }
  248.  
  249. int getqbchar ()
  250. {
  251.     if (nleft > 0) {
  252.         nleft --;
  253.         return *qbptr++;
  254.     }
  255.     qbase = qbase -> qb_forw;
  256.     if (qbase == Header)
  257.         return EOF;
  258.     if (qbase -> qb_data[0] != ' ' && qbase -> qb_data[0] != '\t')
  259.         return EOF;
  260.     nleft = qbase -> qb_len;
  261.     qbptr = qbase -> qb_data;
  262.     return getqbchar ();
  263. }
  264.  
  265. read_header ()
  266. {
  267.     struct qbuf *qp;
  268.     char buffer[BUFSIZ];
  269.     AP_ptr ap;
  270.  
  271.     Header = (struct qbuf *)malloc (sizeof *Header);
  272.     Header -> qb_forw = Header -> qb_back = Header;
  273.  
  274.     while (fgets (buffer, sizeof buffer, stdin) != NULL) {
  275.         if (isheader(buffer)) { /* end of header ? */
  276.             qp = str2qb (buffer, strlen (buffer), 0);
  277.             insque (qp, Header -> qb_back);
  278.         }
  279.         else {
  280.             strcpy (firstline, buffer);
  281.             break;
  282.         }
  283.     }
  284.  
  285.     if (!extract_mode)
  286.         return;
  287.     
  288.     for (qp = Header -> qb_forw; qp != Header; qp = qp -> qb_forw) {
  289.         if (lexnequ (qp -> qb_data, "to:", 3) == 0 ||
  290.             lexnequ (qp -> qb_data, "cc:", 3) == 0 ||
  291.             lexnequ (qp -> qb_data, "bcc:", 4) == 0) {
  292.             qb_read_init (qp);
  293.             for (;;) {
  294.                 ap_pinit (getqbchar);
  295.                 switch (ap_1adr ()) {
  296.                     case DONE:
  297.                     break;
  298.  
  299.                     case NOTOK:
  300.                     adios (NULLCP, "error in address");
  301.                     break;
  302.  
  303.                     default:
  304.                     ap = ap_t2s (ap_pstrt, &eaddr[neaddr++]);
  305.                     ap_free (ap);
  306.                     continue;
  307.                 }
  308.                 break;
  309.             }
  310.         }
  311.     }
  312. }
  313.  
  314.  
  315. send_address (addr)
  316. char    *addr;
  317. {
  318.     int     retval;
  319.     ADDR    *adr;
  320.  
  321.     if (watch) {
  322.         printf ("%s:  ", addr);
  323.         (void) fflush (stdout);
  324.     }
  325.  
  326.     adr = adr_new (addr, AD_822_TYPE, 0);
  327.     if (rp_isbad (retval = io_wadr (adr, AD_RECIPIENT, rp)))
  328.         adios (NULLCP, "Problem in send_address: [%s] %s.",
  329.                rp_valstr (retval),
  330.                rps.rp_line);
  331.  
  332.     adr_tfree (adr);
  333.  
  334.     switch (rp_gval (rp -> rp_val)) {
  335.     case RP_AOK: 
  336.         if(watch) printf ("address ok\n");
  337.         break;
  338.  
  339.     case RP_NO: 
  340.         if(watch) printf ("not deliverable; unknown problem\n");
  341.         badaddrs = TRUE;
  342.         break;
  343.  
  344.     case RP_USER: 
  345.         if(watch) printf ("not deliverable; unknown address.\n");
  346.         badaddrs = TRUE;
  347.         break;
  348.  
  349.     case RP_NDEL: 
  350.         if(watch) printf ("not deliverable; permanent error.\n");
  351.         badaddrs = TRUE;
  352.         break;
  353.  
  354.     case RP_AGN: 
  355.         if(watch) printf ("failed, this attempt; try later\n");
  356.         badaddrs = TRUE;
  357.         break;
  358.  
  359.     case RP_NOOP: 
  360.         if(watch) printf ("not attempted, this time; perhaps try later.\n");
  361.         badaddrs = TRUE;
  362.         break;
  363.  
  364.     default: 
  365.         adios (NULLCP, "Unexpected address response:  %s", rp -> rp_line);
  366.     }
  367.     (void) fflush (stdout);
  368. }
  369.  
  370. doheader(oobto)
  371. char **oobto;
  372. {
  373.     int    gotfrom, gotsender, gotdate, gotrecipient;
  374.     char    line[LINESIZE];
  375.     char    buf[LINESIZE];
  376.     struct qbuf *qp;
  377.  
  378.     gotfrom = gotsender = gotdate = gotrecipient = 0;
  379.     for (qp = Header -> qb_forw; qp != Header; qp = qp -> qb_forw) {
  380.         if (qp -> qb_data[0] == '\n')
  381.             break;
  382.         if (prefix ("Date:", qp -> qb_data))
  383.             gotdate++;
  384.         if (prefix ("From:", qp -> qb_data)) {
  385.             gotfrom++;
  386.             if (rewritefrom) {
  387.                 dofrom();
  388.                 continue;
  389.             }
  390.         }
  391.         if (prefix ("Sender:", qp -> qb_data))
  392.             gotsender++;
  393.         if (prefix ("To:", qp -> qb_data)
  394.             || prefix ("Cc:", qp -> qb_data)
  395.             || prefix ("Bcc:", qp -> qb_data)
  396.             || prefix ("Apparently-To:", qp -> qb_data) )
  397.             gotrecipient++;
  398.  
  399.         if (rp_isbad (io_tdata (qp -> qb_data, qp -> qb_len)))
  400.             adios (NULLCP, "Data copy error");
  401.     }
  402.  
  403.     if (!gotrecipient && oobto) {
  404.         while (*oobto) {
  405.             (void) sprintf (buf, "Apparently-To: %s\n", *oobto++);
  406.             if (rp_isbad (io_tdata (buf, strlen(buf))))
  407.                 adios (NULLCP, "Data copy error");
  408.         }
  409.     }
  410.     if (!gotdate) {
  411.         UTC    now, lut;
  412.         (void) strcpy (buf, "Date: ");
  413.         now = utcnow();
  414.         lut = utclocalise(now);
  415.         UTC2rfc (lut, buf + 6);
  416.         free ((char *) lut);
  417.         (void) strcat (buf, "\n");
  418.         if (rp_isbad (io_tdata (buf, strlen(buf))))
  419.             adios (NULLCP, "Data copy error");
  420.     }
  421.     if (!gotfrom)
  422.         dofrom();
  423.     if (!gotsender) {
  424.         (void) sprintf(buf, "Sender: %s\n", from);
  425.         if (rp_isbad (io_tdata (buf, strlen(buf))))
  426.             adios (NULLCP, "data copy error");
  427.     }
  428.  
  429.     (void) sprintf (tbuf, "1.%s", ia5_bp);
  430.     if (rp_isbad (io_tdend (rp)) || rp_isbad (io_tpart (tbuf, 0, rp)))
  431.         adios (NULLCP, "Error seting up for body part: %s",
  432.                rp -> rp_line);
  433.     if (firstline[0] != '\n')
  434.         io_tdata (firstline, strlen(firstline));
  435.  
  436. }
  437.  
  438. /*
  439.  * Could this be an RFC822 header line?
  440.  */
  441. isheader(line)
  442. char *line;
  443. {
  444.     register char *cp = line;
  445.  
  446.     while (*cp == ' ' || *cp == '\t')
  447.         cp++;
  448.     return *cp == '\n' ? 0 : 1;
  449. }
  450.  
  451. dofrom()
  452. {
  453.     char    line[128];
  454.  
  455.     if (isstr(fullname))
  456.         (void) sprintf(line, "From: %s <%s>\n", fullname, from);
  457.     else
  458.         (void) sprintf(line, "From: %s\n", from);
  459.     io_tdata (line, strlen(line));
  460. }
  461.  
  462. dobody()
  463. {
  464.     char    buffer[BUFSIZ];
  465.     register int    i;
  466.  
  467.     while (!feof (stdin) && !ferror (stdin) &&
  468.         (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0)
  469.         if (rp_isbad (i = io_tdata (buffer, i)))
  470.             adios (NULLCP, "Problem writing body");
  471.  
  472.     if (ferror (stdin))
  473.         adios (NULLCP, "Problem reading body");
  474.  
  475.     if (rp_isbad (io_tdend (rp)) || rp_isbad (io_tend (rp)))
  476.         adios (NULLCP, "problem ending submission: %s", rp -> rp_line);
  477.  
  478.     return(0);    /* eventually the program exit value */
  479. }
  480.  
  481. smtp()
  482. {
  483.     char    *smtpd = dupfpath(chndfldir, SMTPSRVR);
  484.  
  485.     setuid(geteuid());
  486.     execl (smtpd, "sendmail-smtp", "smtp", (char *)0);
  487.     adios ("failed", "execl of %s", smtpd);
  488. }
  489.  
  490. #ifndef lint
  491. static void    adios (va_alist)
  492. va_dcl
  493. {
  494.     va_list ap;
  495.  
  496.     va_start (ap);
  497.  
  498.     _ll_log (pp_log_norm, LLOG_FATAL, ap);
  499.     
  500.     va_end (ap);
  501.  
  502.     _exit (1);
  503. }
  504. #else
  505. /* VARARGS2 */
  506.  
  507. static void    adios (what, fmt)
  508. char   *what,
  509.        *fmt;
  510. {
  511.     adios (what, fmt);
  512. }
  513. #endif
  514.  
  515. static SFD die(sig)
  516. int sig;
  517. {
  518.     io_end(NOTOK);
  519.     adios (NULLCP, "sendmail: dying from signal %d", sig);
  520. }
  521.